﻿using System;
using System.Web.Mvc;
using log4net;
using Microsoft.Practices.Unity;
using TestWebApplication.Models;
using TestWebApplication.Models.Forms;

namespace TestWebApplication.Controllers
{

#if (!DEBUG)
    [RequireHttps]
#endif
    public class AccountController : Controller
    {
        private static readonly ILog LOGGER = LogManager.GetLogger(typeof(AccountController));
        private static int registrationCounter = 0;

        [Dependency]
        public IAuthService AuthService { get; set; }

        [Dependency("GenerateServerExceptionMode")]
        public bool GenerateServerExceptionMode { get; set; }

        public ActionResult Logon()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Logon(LogonForm form, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var isLogon = AuthService.Logon(form.LoginName, form.Password);
                if (isLogon)
                {
                    LOGGER.InfoFormat("Пользователь '{0}' успешно вошел в систему", form.LoginName);

                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1
                        && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }

                    return RedirectToAction("Index", "Home");
                }

                LOGGER.WarnFormat("Пользователю '{0}' было отказано в доступе", form.LoginName);
                ModelState.AddModelError("", "Вы указали неверный логин и/или пароль. Попробуйте еще раз.");
                form.Password = "";
            }

            return View(form);
        }

        public ActionResult Logoff()
        {
            if (Request.IsAuthenticated)
            {
                AuthService.Logoff();
                LOGGER.InfoFormat("Пользователь '{0}' вышел из системы",
                    HttpContext.User.Identity.Name);
            }

            return RedirectToAction("Index", "Home");
        }

        public ActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Register(UserRegistrationForm form)
        {
            try
            {
                // генерируем случайное исключение
                GenerateServerException();

                if (ModelState.IsValid)
                {
                    if (form.GetBirthayAsDateTime() > DateTime.Now)
                    {
                        throw new BirthdayException();
                    }

                    var baseUrl = GetBaseUrl();
                    AuthService.RegisterUser(form, baseUrl);

                    LOGGER.InfoFormat("Пользователь '{0}' создан в системе, но не активирован", form.LoginName);
                    
                    return RedirectToAction("RegisterInfo");
                }
            }
            catch(ExistsUserLoginException)
            {
                ModelState.AddModelError("",
                    string.Format("Логин '{0}' уже используется. Введите другое значение.", form.LoginName));
                LOGGER.WarnFormat("Попытка зарегистрировать пользователя на уже существующий логин '{0}'",
                    form.LoginName);

                form.LoginName = "";
            }
            catch(BirthdayException)
            {
                const string message = "Была указана некорректная дата рождения";
                ModelState.AddModelError("", message);
                LOGGER.Warn("Регистрация пользователя не удалась: " + message);
            }
            catch(EmailNotificationException ex)
            {
                ModelState.AddModelError("", "Не удалось отправить письмо о подтверждении регистрации. Попробуйте еще раз.");
                LOGGER.Error("Ошибка во время регистрации пользователя: " + ex);
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("", "В процессе регистрации произошла ошибка сервера. Попробуйте еще раз.");
                LOGGER.Error("Ошибка во время регистрации пользователя: " + ex);
            }

            // очищаем поле пароля при серв. валидации
            form.Password = "";
            form.ConfirmPassword = "";
            
            return View(form);
        }

        public ActionResult RegisterInfo()
        {
            return View();
        }

        public ActionResult RegisterSuccess()
        {
            return View();
        }

        public ActionResult RegisterComplete(string key)
        {
            if (! AuthService.HasCreatedUser(key))
            {
                return RedirectToAction("Logon");
            }

            return View(new RegisterCompleteForm());
        }

        [HttpPost]
        public ActionResult RegisterComplete(RegisterCompleteForm form, string key)
        {
            if (!AuthService.HasCreatedUser(key))
            {
                return RedirectToAction("Logon");
            }

            try
            {
                if (ModelState.IsValid)
                {
                    var loginName = AuthService.ActivateUser(key, form.Size);
                    LOGGER.InfoFormat("Пользователь '{0}' успешно активирован в системе", loginName);

                    return RedirectToAction("RegisterSuccess");
                }
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("", "Произошла ошибка во время процедуры активации. Обратитесь в техподдержку.");
                LOGGER.ErrorFormat("Во время активации пользователя произошла ошибка: " + ex);
            }

            return View(form);
        }

        private void GenerateServerException()
        {
            if (! GenerateServerExceptionMode)
            {
                return;
            }

            registrationCounter++;

            if (registrationCounter % 10 == 0)
            {
                throw new InvalidOperationException("Эмуляция серверного исключения");
            }
        }
        
        private string GetBaseUrl()
        {
            return Request.Url.Scheme + "://" + Request.Url.Authority;
        }

    }
}
